package com.projecy.config.security;


import com.projecy.common.utils.RedisUtil;
import com.projecy.config.filter.JwtAuthorizationFilter;
import com.projecy.system.service.SysMenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.HttpStatusEntryPoint;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.filter.CorsFilter;
import org.zalando.problem.spring.web.advice.security.SecurityProblemSupport;


//添加SecurityProblemSupport来处理安全异常捕捉
@Import(SecurityProblemSupport.class)
//开启基于方法的安全认证机制
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
    @Autowired
    CorsFilter corsFilter;

    @Autowired
    SecurityProblemSupport securityProblemSupport;

    @Autowired
    SysMenuService menuService;
    @Autowired
    RedisUtil redisUtil;

    @Bean//配置SpringSecurity推荐的加密方式
    public PasswordEncoder passwordEncoder(){
        System.out.println("Security密码加密");
        return new BCryptPasswordEncoder();
    }

    //配置不进入SpringSecurity的名单,如果要在SpringSecurity中配置，需要在JwtAuthorizationFilter单独处理
    @Override
    public void configure(WebSecurity webSecurity){//
        System.out.println("配置不进入SpringSecurity的名单,如果要在SpringSecurity中配置，需要在JwtAuthorizationFilter单独处理");
        webSecurity.ignoring()
                .antMatchers(HttpMethod.POST,"/auth/login");
    }

    //设置安全策略
    @Override
    public void configure(HttpSecurity httpSecurity) throws Exception {
        System.out.println("设置HttpSecurity的安全策略");
        httpSecurity
                .addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class)
                .exceptionHandling()
                // 当用户无权访问资源时发送 401 响应
                .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
                // 当用户访问资源因权限不足时发送 403 响应
                .accessDeniedHandler(securityProblemSupport)
                .and()
                // 禁用 CSRF
                .csrf().disable()
                .headers().frameOptions().disable()
                .and()
                .authorizeRequests()
                // 配置不需要验证的请求地址
                // 其他请求需验证
                .anyRequest().authenticated()
                .and()
                // 不需要 session（不创建会话）
                .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .apply(securityConfigurationAdapter());
    }

    //将HttpSecurity的安全策略移交给JWT
    private JwtConfigurerAdapter securityConfigurationAdapter() throws Exception {
        System.out.println("将HttpSecurity的安全策略移交给JWT");
        return new JwtConfigurerAdapter(new JwtAuthorizationFilter(authenticationManager(), menuService, redisUtil));
    }
}
